using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Windows;

namespace ContractDocumentation
{
    class PortTypeHelper
    {
        static XNamespace wsdl = "http://schemas.xmlsoap.org/wsdl/";
        static XNamespace xs = "http://www.w3.org/2001/XMLSchema";

        internal static XmlClass ExtractPortType(Context context, XElement portTypeElement)
        {
            XNamespace targetNamespace = (string)portTypeElement.Parent.Attribute("targetNamespace");
            return new XmlClass()
            {
                Name = targetNamespace + (string)portTypeElement.Attribute("name"),
                Documentation = XmlUtils.GetWsdlDocumentation(portTypeElement),
                Methods = (from operationElement in portTypeElement.Elements(wsdl + "operation")
                          select new XmlMethod()
                          {
                              Name = targetNamespace + (string)operationElement.Attribute("name"),
                              Documentation = XmlUtils.GetWsdlDocumentation(operationElement),
                              ReturnValue = GetInputOrOutputParameters(context, operationElement.Element(wsdl + "output")).SingleOrDefault(),
                              Parameters = GetInputOrOutputParameters(context, operationElement.Element(wsdl + "input")),
                          }).ToList(),

            };
        }

        static IList<XmlParameter> GetInputOrOutputParameters(Context context, XElement inputOrOutputElement)
        {
            var messageElementName = XmlUtils.GetXName(inputOrOutputElement, (string)inputOrOutputElement.Attribute("message"));
            return (from messageElement in XmlUtils.GetMessageDefinitionAsSequence(context, messageElementName)
                   from partElement in messageElement.Elements(wsdl + "part")
                   let wrappingElementName = XmlUtils.GetXName(partElement, (string)partElement.Attribute("element"))
                   from wrappingElement in XmlUtils.GetElementDefinitionAsSequence(context, wrappingElementName)
                   let targetNamespace = (XNamespace)(string)wrappingElement.Parent.Attribute("targetNamespace")
                   from complexTypeElement in wrappingElement.Elements(xs + "complexType")
                   from sequenceElement in complexTypeElement.Elements(xs + "sequence")
                   from element in sequenceElement.Elements(xs + "element")
                   select new XmlParameter()
                   {
                       Name = targetNamespace + (string)element.Attribute("name"),
                       XmlType = GetXmlType(context, element),
                       Documentation = XmlUtils.GetXsDocumentation(element),
                   }).ToList();
        }

        static XmlType GetXmlType(Context context, XElement element)
        {
            if ((string)element.Attribute("type") == null)
            {
                var q = from complexTypeElement in element.Elements(xs + "complexType")
                        from sequenceElement in complexTypeElement.Elements(xs + "sequence")
                        from elementElement in sequenceElement.Elements(xs + "element")
                        select elementElement;
                element = q.FirstOrDefault();
            }
            if ((string)element.Attribute("type") == null) return null;
            return new XmlType()
            {
                Type = XmlUtils.GetXName(element, (string)element.Attribute("type")),
                IsArray = XmlUtils.GetMaxOccurs(element) > 1,
            };
        }
    }
}
